package net.esj.basic.translate.bean;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import net.esj.basic.core.engine.support.translator.Translator;
import net.esj.basic.core.view.support.vojo.BaseVojo;
import net.esj.basic.core.view.support.vojo.StaticsObject;
import net.esj.basic.core.view.support.vojo.TransObject;
import net.esj.basic.core.view.support.vojo.annotation.StaticMatch;
import net.esj.basic.pojo.PrimaryKey;
import net.esj.basic.service.Service;
import net.esj.basic.translate.defaults.DefaultsPoAndVoTranslator;
import net.esj.basic.translate.vo.BasicStaticsVo;
import net.esj.basic.utils.ClassUtils;
import net.esj.basic.utils.ConstantsManager;
import net.esj.basic.utils.Validators;

import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

//@org.springframework.stereotype.Service("translateBean")
/**
 * @see Translator
 * @see DefaultsPoAndVoTranslator
 */
@Deprecated
public class TranslateBean implements ApplicationContextAware{
	
	private Service service;

	ApplicationContext applicationContext;
	
	private void translateVo(Object source,Object target) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchFieldException, InstantiationException{
		
		Class<?> actualEditable = target.getClass();
		PropertyDescriptor[] targetPds =BeanUtils.getPropertyDescriptors(actualEditable);
		
		
		for (PropertyDescriptor targetPd : targetPds) {
			if (targetPd.getWriteMethod() != null ) {
				PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
				if (sourcePd != null && sourcePd.getReadMethod() != null) {
					Method readMethod = sourcePd.getReadMethod();
					if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
						readMethod.setAccessible(true);
					}
					Object value = readMethod.invoke(source);
					
					if(value==null){
						continue;
					}
					
					Method writeMethod = targetPd.getWriteMethod();
					if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
						writeMethod.setAccessible(true);
					}
					
					
					if(ClassUtils.isInterfaceOf(targetPd.getPropertyType(),StaticsObject.class)){//静态VO自动从对象文件中获取
						value = transStaticVo(value, targetPd.getPropertyType());
						writeMethod.invoke(target, value);
						continue;
					}
					/*else if(ClassUtils.isInterfaceOf(targetPd.getPropertyType(), TransObject.class)){//如果目标是TransObject的实例，则递归传递
						if(! (value instanceof HibernateProxy)){
							value = translateVo(value, targetPd.getPropertyType());
						}else{
							LazyInitializer lazyInitializer = ((HibernateProxy)value).getHibernateLazyInitializer();
							Object val =  targetPd.getPropertyType().newInstance();
							if(lazyInitializer.isUninitialized()){
								if(val instanceof BaseVojo){
									((BaseVojo)val).setId((String)lazyInitializer.getIdentifier());
								}else{
									value = lazyInitializer.getIdentifier();
								}
							}else{
								val = translateVo(lazyInitializer.getImplementation(), targetPd.getPropertyType());
							}
							value = val;
						}
					}*/
					
					if(value instanceof HibernateProxy ){//如果为HIBERNATE的代理 1：已被初始化则继承 2：未初始化则新增且赋值ID
						LazyInitializer lazyInitializer = ((HibernateProxy)value).getHibernateLazyInitializer();
						//Object val =  targetPd.getPropertyType().newInstance();
			            if(lazyInitializer.isUninitialized()) {
			            	if(BaseVojo.class.isAssignableFrom(targetPd.getPropertyType())){
			            		//value = translateVo( baseService.get(lazyInitializer.getIdentifier(), sourcePd.getPropertyType()),targetPd.getPropertyType());
			            		value  = targetPd.getPropertyType().newInstance();
			            		((BaseVojo)value).setId((String) lazyInitializer.getIdentifier());
			            	}else if(PrimaryKey.class.isAssignableFrom(targetPd.getPropertyType())){
			            		// value = baseService.get(lazyInitializer.getIdentifier(), sourcePd.getPropertyType());
			            		value = sourcePd.getPropertyType().newInstance();
			            		((PrimaryKey)value).setId((String) lazyInitializer.getIdentifier());
			            	}else{
			            		value = lazyInitializer.getIdentifier();
			            	}
			            	//value =translateVo( baseService.get(lazyInitializer.getIdentifier(), sourcePd.getPropertyType()),targetPd.getPropertyType());
			            }else{
			            	if(BaseVojo.class.isAssignableFrom(targetPd.getPropertyType())){
			            		value = translateVo( lazyInitializer.getImplementation(), targetPd.getPropertyType());
			            	}else if(PrimaryKey.class.isAssignableFrom(targetPd.getPropertyType())){
			            		value = lazyInitializer.getImplementation();
			            	}else{
			            		value = lazyInitializer.getImplementation();
			            	}
			            }
			            writeMethod.invoke(target, value);
			            continue;
					}
					
					if(ClassUtils.isInterfaceOf(targetPd.getPropertyType(), TransObject.class)){
						value = translateVo(value, targetPd.getPropertyType());
						writeMethod.invoke(target, value);
						continue;
					}
					
					writeMethod.invoke(target, value);
					
				}
			}
		}
	}
	
	private <T> Object transStaticVo(Object source,Class<T> targetClass){
		try {
			T o = ClassUtils.newInstance(targetClass);
			if(Validators.isEmpty(source)){
				return o;
			}
			StaticMatch sm = targetClass.getAnnotation(StaticMatch.class);
			if(sm==null){
				return o;
			}
			String name = sm.value();
			switch(sm.type()){
			case HIBERNATE_MAP:
				Class<?> clazz = Class.forName(name);
				Object s = null;
				if(source instanceof HibernateProxy){
					LazyInitializer lazyInitializer = ((HibernateProxy)source).getHibernateLazyInitializer();
		            if(lazyInitializer.isUninitialized()) {
		            	s = service.get(lazyInitializer.getIdentifier(), clazz);
		            }else{
		            	s = source;
		            }
				}else if(source instanceof PrimaryKey){
					s = service.get((Serializable)((PrimaryKey)source).getId(), clazz);
				}
				else{
					s = service.get((Serializable)source, clazz);
				}
				if(s==null){
					return o;
				}
				translateVo(s, o);
				break;
			case JSON_FILE:
				JSONObject jo = ConstantsManager.getJsonObject(name,  source.toString());
				if(jo==null){
					return o;
				}
				Iterator it = jo.keys();
				while(it.hasNext()){
					String k = (String) it.next();
					String v = jo.getString(k);
					PropertyDescriptor targetPd = BeanUtils.getPropertyDescriptor(targetClass, k);
					if (targetPd != null && targetPd.getWriteMethod() != null) {
						Method writeMethod = targetPd.getWriteMethod();
						if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
							writeMethod.setAccessible(true);
						}
						writeMethod.invoke(o, v);
					}
				}
				break;
			}
			return o;
		} catch (Throwable ex) {
			throw new FatalBeanException("Could not copy static vo from source to target", ex);
		}
	}
	
	public <T> Object translateVo(Object source,Class<T> targetClass) {
		try{
			if(source instanceof Collection){
				List<T> list = new ArrayList<T>();
				for(Object object : (Collection)source){
					T o = targetClass.newInstance();
					try{
						translateVo(object,o);
						list.add(o);
					}catch(Throwable e){
						e.printStackTrace();
					}
				}
				return list;
			}else if(source.getClass().isArray()){
				T[] ts = (T[]) Array.newInstance(targetClass, Array.getLength(source));
				for(int i=0;i<Array.getLength(source);i++){
					T o = targetClass.newInstance();
					try{
						translateVo(source, o);
						ts[i] = o;
					}catch(Throwable e){
						
					}
				}
				return ts;
			}else{
				Object o = targetClass.newInstance();
				translateVo(source, o);
				return o;
			}
		}catch(Throwable ex){
			throw new FatalBeanException("Could not copy properties from source to target", ex);
		}
	}
	
	public void translatePo(Object source,Object target){
		try{
			Class<?> actualEditable = target.getClass();
			PropertyDescriptor[] targetPds =BeanUtils.getPropertyDescriptors(actualEditable);
			
			for (PropertyDescriptor targetPd : targetPds) {
				if (targetPd.getWriteMethod() != null ) {
					
					PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
					if (sourcePd != null && sourcePd.getReadMethod() != null) {
						Method readMethod = sourcePd.getReadMethod();
						if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
							readMethod.setAccessible(true);
						}
						Object value = readMethod.invoke(source);
						
						
						if(value instanceof BasicStaticsVo){
							value =( (BasicStaticsVo)value).getId();
						}else if(value instanceof TransObject){
							Object o = targetPd.getPropertyType().newInstance();
							translatePo(value, o);
							value =o;
						}
						
						Method writeMethod = targetPd.getWriteMethod();
						writeMethod.invoke(target, value);
						
						
//						if(ClassUtils.isInterfaceOf(targetPd.getPropertyType(), TranslateBean.class)){//如果value是translatebean的实例，则递归传递
//							value = translateVo(value, targetPd.getPropertyType());
//						}
					}
				}
			}
		}catch(Throwable ex){
			throw new FatalBeanException("Could not copy properties from source to target", ex);
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext arg0)
			throws BeansException {
		applicationContext = arg0;
	}

	public Service getService() {
		if(service==null){
			service = applicationContext.getBean(Service.class);
		}
		return service;
	}

	
}
